// require中可以存放 相对文件或绝对路径，可以省略.js,.json的后缀
/* const r = require('./a');
console.log(r); */

/**
 * 1.先去读取a文件，拿到a文件的内容，进行函数包裹
 *  (function(mocule, exports, require, __dirname, __filename) {
 *    module.exports = 'hello';
 *    return module.exports;
 *  })(mocule, exports, require, __dirname, __filename)
 * 2. 执行函数，传入vm，让函数执行
 */

/**
 *  怎么调试？
 *  1. node --inspect-brk a.js,实现调试功能，借助浏览器控制台来调试
 *   在浏览器输入：chrome://inspect
 *  2. 利用vscode调试
 */

const fs = require('fs');
const path = require('path');
const vm = require('vm');

function Module(filename) {
  this.id = filename;
  this.exports = {};
  this.path = path.dirname(filename); // 父目录
}
// 模块加载
Module.prototype.load = function () {
  // 加载时，需要获取文件的后缀名，根据后缀名采用不同的策略进行加载
  let extensions = path.extname(this.id);
  console.log(extensions);
  Module._extensions[extensions](this);
};
// 将字符串包裹成一个字符串函数
Module.wrapper = function (content) {
  return `(function(exports, require, module, __dirname, __filename) {${content}})`;
};
// 缓存模块
Module._cache = {};
Module._extensions = {};
Module._extensions['.js'] = function (module) {
  let content = fs.readFileSync(module.id, 'utf8');

  // 根据内容包裹一个函数
  let str = Module.wrapper(content);
  console.log(str);
  // 让字符串变成函数
  let fn = vm.runInThisContext(str);
  let exports = module.exports;
  // 改变this指向module.exports
  fn.call(exports, exports, myReq, module, module.id, module.path);
  // 这句话执行完，module.exports = hello；
};
Module._extensions['.json'] = function (module) {
  let content = fs.readFileSync(module.id, 'utf8');
  module.exports = JSON.parse(content); // 手动将json的结果过载在module.exports上
};

Module._resolveFilename = function (filename) {
  let filePath = path.resolve(__dirname, filename);
  let isExists = fs.existsSync(filePath);
  if (isExists) return filePath;
  // console.log(isExists);
  let keys = Reflect.ownKeys(Module._extensions);
  for (let i = 0; i < keys.length; i++) {
    let newFile = filePath + keys[i];
    if (fs.existsSync(newFile)) {
      return newFile;
    }
  }
  throw new Error('module no found');
};

function myReq(filename) {
  // 1. 解析当前文件的文件名
  filename = Module._resolveFilename(filename);
  if (Module._cache[filename]) {
    return Module._cache[filename].exports;
  }
  console.log(filename);
  // 2. 创建模块
  let module = new Module(filename);

  Module._cache[filename] = module;
  console.log(module);
  // module.exports = 'hello'; 将导入的文件内容赋值到module.exports
  // 3. 加载模块
  module.load();
  return module.exports;
}
// module.exports 重新赋值了  exports指针改变了
let r = myReq('./a.js'); // 默认只识别module.exports
/* myReq('./a.js');
myReq('./a.js');
myReq('./a.js');
myReq('./a.js'); */
console.log(r);
// 模块导出不能使用 exports = xxx;因为内部是使用 module.exports = exports, exports = xx，会改变exports的引用地址，module.exports就没有赋上值
// 正确的是：module.exports, exports.a, module.exports.a
